<!-- 下拉刷新组件 -->
<template>
  <div
    class="pull_to_refresh"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
  >
    <div
      class="refresh-wrapper"
      :style="{
        color: tipColor,
        fontSize: tipSize + `px`,
        height: refreshHeight + 'px',
        backgroundColor: bgColor,
        transition: transitonStatus,
      }"
      v-show="isShow"
    >
      <span>{{ tipTxt }}</span>
    </div>
    <div class="content-wrapper">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: "pullToRefresh",
};
</script>

<script setup>
import { computed, reactive } from "vue";
import { DefaultTips, DefaultConfing } from "./cong";
const emit = defineEmits(["refreshed", "refreshing"]);

//传入的配置项
const props = defineProps({
  //下拉刷新的文字颜色
  tipColor: {
    type: String,
    default: DefaultConfing.TIP_COLOR,
  },
  //下拉刷新的文字大小
  tipSize: {
    type: Number,
    default: DefaultConfing.TIP_SIZE,
  },
  //下拉刷新的背景颜色
  bgColor: {
    type: String,
    default: DefaultConfing.BG_COLOE,
  },
});

//是否显示的状态
const stateObj = reactive({
  //是否显示下拉刷新
  isShow: false,
  //高度
  refreshHeight: 0,
});

//下拉刷新需要显示的文字
let tipTxt = ref(DefaultTips.WILL_PULL_TIP);

//是否是加载中的状态
let isLoading = false;

//是否需要过度动画
let isNeedTrasiton = false;

//刷新的位置对象
const postion = reactive({
  //开始位置和结束位置
  start: 0,
  end: 0,
});

//下拉刷新的过度动画
const transitonStatus = computed(() => {
  return isNeedTrasiton ? `height .${DefaultConfing.ANIM_DURATION}s` : `none`;
});

//通过toRefs
const { isShow, refreshHeight } = toRefs(stateObj);

//开始触摸
const handleTouchStart = (e) => {
  const touch = e.changedTouches[0];
  //记录Y的开始位置
  postion.start = touch.clientY;
};

//移动
const handleTouchMove = (e) => {
  if (!isLoading) {
    //显示下拉刷新
    setRefreshShow(true);
    const touch = e.changedTouches[0];
    //记录下移动的结束位置
    postion.end = touch.clientY;
    //记录移动的距离
    const diffHeight = postion.end - postion.start;
    if (stateObj.refreshHeight > DefaultConfing.MIN_REFRESH_HEIGTH) {
      setTip(DefaultTips.PULLING_TIP);
    }

    if (postion.start > postion.end) {
      //从下往上
      addRefreshHeight(diffHeight);
    } else {
      //从上往下
      addRefreshHeight(diffHeight / 2);
    }

    postion.start = postion.end;
  }
};

//结束触摸
const handleTouchEnd = (e) => {
  setNeedTrasiton(true);
  if (stateObj.refreshHeight < DefaultConfing.MIN_REFRESH_HEIGTH) {
    //小于最小高度
    resetRefresh();
  } else {
    //大于最小高度
    setRefreshState();
    setTimeout(() => {
      resetRefresh();
      emit("refreshed");
    }, DefaultConfing.LOADING_DURATION);
  }
};

//大于最小高度的时候设置方法
const setRefreshState = () => {
  setRefreshHeight(DefaultConfing.MIN_REFRESH_HEIGTH);
  setTip(DefaultTips.LOADING_TIP);
  setLoading(true);
  emit("refreshing");
};

//还原状态
const resetRefresh = () => {
  //还原高度
  setRefreshHeight(0);
  setTip(DefaultTips.WILL_PULL_TIP);
  setLoading(false);
  closeRefreshArea();
};

//ANIM_DURATION时间后还原
const closeRefreshArea = () => {
  setTimeout(() => {
    setNeedTrasiton(false);
    setRefreshShow(false);
  }, DefaultConfing.ANIM_DURATION * 1000);
};

//设置下拉刷新的文字
const setTip = (value) => {
  tipTxt.value = value;
};

//设置加载中的状态
const setLoading = (value) => {
  isLoading = value;
};

//设置动画
const setNeedTrasiton = (isNeedTrasiton) => {
  isNeedTrasiton = isNeedTrasiton;
};

//设置下拉刷新的高度
const setRefreshHeight = (height) => {
  stateObj.refreshHeight = height;
};

//增加下拉刷新的高度
const addRefreshHeight = (diffHeight) => {
  stateObj.refreshHeight += diffHeight;
};

//设置是否显示下拉刷新
const setRefreshShow = (isShow) => {
  stateObj.isShow = isShow;
};
</script>

<style lang="scss" scoped>
.pull_to_refresh {
  height: 100%;
  overflow-y: auto;
  .refresh-wrapper {
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
</style>
